package com.henu.acmrating.crawler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.henu.acmrating.pojo.Problem;
import com.henu.acmrating.pojo.UserOj;
import com.henu.acmrating.service.ProblemService;
import com.henu.acmrating.service.UserOjService;
import com.henu.acmrating.utils.DateUtils;
import com.henu.acmrating.utils.LeetcodeUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.*;
import us.codecraft.webmagic.model.HttpRequestBody;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.utils.HttpConstant;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;

/**
 * @Author XiaolongLi
 * @Description TODO
 * @Date 2020/12/6 11:11
 */
@Component
public class LeetcodeProcessor implements PageProcessor {

    private static final String OJ_NAME = "Leetcode";
    private static final String BASE_URL = "https://leetcode-cn.com/graphql/";

    @Resource
    UserOjService userOjService;

    @Resource
    ProblemService problemService;

    public static LeetcodeProcessor leetcodeProcessor;

    @PostConstruct
    public void init() {
        leetcodeProcessor = this;
    }

    @Override
    public void process(Page page) {
        Html html = page.getHtml();
        ResultItems resultItems = page.getResultItems();
        String account = resultItems.getRequest().getHeaders().get("Referer-Type").split("/")[4];
        JSONObject jsonObject = JSON.parseObject(page.getJson().toString());
        UserOj userOj = leetcodeProcessor.userOjService.selectByAccountAndOjName(account, OJ_NAME);
        if (jsonObject.getJSONObject("data").getJSONObject("userProfilePublicProfile") != null) {
            process2(jsonObject, userOj);
        } else {
            process1(jsonObject, userOj);
        }


    }

    // 爬取最近刷题记录
    void process1(JSONObject jsonObject, UserOj userOj) {
        JSONArray jsonArray = jsonObject.getJSONObject("data").getJSONArray("recentSubmissions");
        int lastId = userOj.getLastId();
        int maxRunId = 0;
        List<Problem> problemList = new LinkedList<>();
        Set<String> acProblemSet = new HashSet<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject info = jsonArray.getJSONObject(i);
            String lang = LeetcodeUtils.langTo(info.getString("lang"));
            String status = LeetcodeUtils.statusTo(info.getString("status"));
            Date submitTime = DateUtils.timeStamp2Date(info.getLong("submitTime") * 1000);
            String runtime = info.getString("runtime");
            String memory = info.getString("memory");
            if (runtime.equals("N/A")) runtime = "";
            if (memory.equals("N/A")) memory = "";
            String url = "https://leetcode-cn.com/problems/" + info.getJSONObject("question").getString("titleSlug");
            String title = info.getJSONObject("question").getString("translatedTitle");
            String id = info.getString("id");
            // 构造新问题
            Problem problem = new Problem(userOj.getUserId(), OJ_NAME, id, title, url, submitTime, status, lang, memory, runtime);
            int nowRunId = Integer.parseInt(problem.getRunId());

            maxRunId = Math.max(maxRunId, nowRunId);
            if (nowRunId == lastId) {
                break;
            }
            problemList.add(problem);

            if (BaseProcessor.isContain(problem.getSubmitStatus())) {
                acProblemSet.add(problem.getProblemUrl());
            }
           
        }
        BaseProcessor.insertDataBase(leetcodeProcessor.problemService, userOj, acProblemSet, problemList, maxRunId, leetcodeProcessor.userOjService);

    }

    // 第一次绑定爬取总题数
    void process2(JSONObject jsonObject,  UserOj userOj) {
        JSONObject result = jsonObject.getJSONObject("data").getJSONObject("userProfilePublicProfile").getJSONObject("submissionProgress");
        Integer totalSubmissions = result.getInteger("totalSubmissions");
        Integer acTotal = result.getInteger("acTotal");
        userOj.setSubmissions(totalSubmissions);
        userOj.setSolved(acTotal);
        leetcodeProcessor.userOjService.updateByPrimaryKeySelective(userOj);
    }

    private final Site site = Site.me().setCharset("UTF-8")
            .setTimeOut(15 * 1000)  // 设置超时时间
            .setRetrySleepTime(3000)// 设置重试的间隔时间
            .setRetryTimes(3);      // 设置重试次数

    @Override
    public Site getSite() {
        return site;
    }


    @Scheduled(cron = "0 15 5 ? * * ")
    public void start() {
        Spider spider = Spider.create(new LeetcodeProcessor())
                .thread(1);
        List<Request> graphQLs = BaseProcessor.getGraphQLs(userOjService, OJ_NAME, BASE_URL);
        for (Request request : graphQLs) {
            spider.addRequest(request);
        }
        spider.start();
    }

    public static void run_all() {
        Spider spider = Spider.create(new LeetcodeProcessor())
                .thread(1);
        List<Request> graphQLs = BaseProcessor.getGraphQLs(leetcodeProcessor.userOjService, OJ_NAME, BASE_URL);
        for (Request request : graphQLs) {
            spider.addRequest(request);
        }
        spider.start();
    }

    public static void run(String id) {

        Request request = new Request(BASE_URL);
        request.setMethod(HttpConstant.Method.POST);
        request.addHeader("Referer-Type", "https://leetcode-cn.com/u/" + id);
        request.setRequestBody(HttpRequestBody.json(" { \"variables\": { \"userSlug\": \"" + id + "\" }, \"query\": \"query recentSubmissions($userSlug: String!) {recentSubmissions(userSlug: $userSlug) {id status lang question {  questionFrontendId  title  translatedTitle  titleSlug  __typename  }  submitTime   runtime memory}}\"}", "utf-8"));


        Request request1 = new Request(BASE_URL);
        request1.setMethod(HttpConstant.Method.POST);
        request1.addHeader("Referer-Type", "https://leetcode-cn.com/u/" + id);
        request1.setRequestBody(HttpRequestBody.json("{\"query\": \"query userPublicProfile($userSlug:String!){userProfilePublicProfile(userSlug:$userSlug){submissionProgress{totalSubmissions acTotal}}}\",\"variables\": { \"userSlug\": \"" + id + "\" }}", "utf-8"));

        Spider.create(new LeetcodeProcessor())
                .addRequest(request)
                .addRequest(request1)
                .thread(1)
                .start();
    }

    public static void main(String[] args) {
        Request request = new Request(BASE_URL);
        request.setMethod(HttpConstant.Method.POST);
        request.addHeader("Referer-Type", "https://leetcode-cn.com/u/vB1LecYE08/");
        request.setRequestBody(HttpRequestBody.json(" { \"variables\": { \"userSlug\": \"vB1LecYE08\" }, \"query\": \"query recentSubmissions($userSlug: String!) {recentSubmissions(userSlug: $userSlug) {id status lang question {  questionFrontendId  title  translatedTitle  titleSlug  __typename  }  submitTime   runtime memory}}\"}", "utf-8"));


        String id = "vB1LecYE08";
        Request request1 = new Request("https://leetcode-cn.com/graphql/");
        request1.setMethod(HttpConstant.Method.POST);
        request1.addHeader("Referer-Type", "https://leetcode-cn.com/u/" + id);
        request1.setRequestBody(HttpRequestBody.json("{\"query\": \"query userPublicProfile($userSlug:String!){userProfilePublicProfile(userSlug:$userSlug){submissionProgress{totalSubmissions acTotal}}}\",\"variables\": { \"userSlug\": \"" + id + "\" }}", "utf-8"));

        Spider.create(new LeetcodeProcessor())
                .addRequest(request)
                .addRequest(request1)
                .thread(1)
                .start();
    }
}

